home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Whiteline: Alpha
/
Whiteline Alpha.iso
/
progtool
/
modula2
/
hk_lib
/
def_mod
/
xstrings.mod
< prev
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Modula Implementation
|
1994-09-22
|
35.9 KB
|
1,030 lines
IMPLEMENTATION MODULE XStrings;
(*****************************************************************************)
(* August '89 Beginn *)
(* 21-Sep-89 , hk *)
(* Erste Version *)
(* 21-Okt-89 , hk *)
(* Aufspaltung in zwei Module (-> "Strings" ) *)
(* Aenderungen hier: Bis auf "TrimXXX", "CompareNoCase" ist alles neu*)
(* 05-Dez-89 *)
(* "FillString","ConvertStr","EqualConvStr","CompareNoCase", *)
(* "TrimRight" in Assembler *)
(*****************************************************************************)
FROM SYSTEM IMPORT (* PROC *) VAL, INLINE;
FROM Chars IMPORT (* TYPE *) CharConvert, CharClassTest;
FROM Strings IMPORT (* TYPE *) CompareResult,
(* PROC *) Length;
(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
CONST EOS = 0C; (* End Of String -- dynamisches Stringende *)
(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
PROCEDURE FillStr ((* EIN/ -- *) fuellung : CHAR;
(* EIN/ -- *) anzahl : CARDINAL;
(* -- /AUS *) VAR string : ARRAY OF CHAR );
(*T*)
(* VAR Index : CARDINAL; *)
BEGIN
(* IF ( anzahl = 0 ) OR ( anzahl > VAL( CARDINAL, HIGH( string ))) THEN
anzahl := HIGH( string );
ELSE
string[ anzahl ] := EOS;
DEC( anzahl );
(* HIGH(string) koennte auch Null sein,
* deswegen nur hier verringern und nicht
* in der FOR-Schleife bis <anzahl> - 1
*)
END;
FOR Index := 0 TO anzahl DO
string[ Index ] := fuellung;
END;
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
string EQU 12
HIGH EQU string + 4
anzahl EQU HIGH + 2
fuellung EQU anzahl + 2
FillStr:
move.b fuellung(a6), d1
movea.l string(a6), a0
move.w anzahl(a6), d0
subq.w #1, d0 ; falls <anzahl> = 0 -> anzahl = MAX(CARD)
cmp.w HIGH(a6), d0 ; IF anzahl > HIGH( string ) THEN
blo.s term ;
move.w HIGH(a6), d0 ; anzahl := HIGH( string );
bra.s fillp ; ELSE
term:
clr.b 1(a0,d0.w) ; string[anzahl] := EOS;
fillp: ; END;
move.b d1, (a0)+
dbra d0, fillp
*)
INLINE( 122EH,0014H,206EH,000CH,302EH,0012H,5340H,0B06EH,0010H );
INLINE( 6506H,302EH,0010H,6004H,4230H,0001H,10C1H,51C8H,0FFFCH );
END FillStr;
(* ------------------------------------------------------------------------- *)
PROCEDURE ConvertStr ((* EIN/ -- *) quelle : ARRAY OF CHAR;
(* EIN/ -- *) convert : CharConvert;
(* -- /AUS *) VAR ziel : ARRAY OF CHAR;
(* -- /AUS *) VAR vollst : BOOLEAN );
(*T*)
(* VAR Index,
MaxIndex : CARDINAL; *)
BEGIN
(* IF HIGH( quelle ) > HIGH( ziel ) THEN
MaxIndex := HIGH( ziel );
ELSE
MaxIndex := HIGH( quelle );
END;
Index := 0;
WHILE ( Index <= MaxIndex ) & ( quelle[ Index ] # EOS ) DO
(* (0<=Index<=HIGH(quelle)) & (0<=Index<=HIGH(ziel)) &
* ((0<=i<Index) => (ziel[i]=convert(quelle[i]))) &
* ((0<=i<=Index) => (quelle[i] # EOS))
*)
ziel[ Index ] := convert( quelle[ Index ] );
INC( Index );
END;
(* ((Index=HIGH(ziel)+1) OR (Index=HIGH(quelle)+1) OR
* (quelle[Index]=EOS) ) &
* ((0<=i<Index) => (ziel[i]=convert(quelle[i]) # EOS ))
*)
IF ( Index > VAL( CARDINAL, HIGH( quelle ))) OR
( quelle[ Index ] = EOS )
THEN
vollst := TRUE;
IF Index <= VAL( CARDINAL, HIGH( ziel )) THEN
ziel[ Index ] := EOS;
END;
ELSE
vollst := FALSE;
END;
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vollst EQU 12
ziel EQU vollst + 4 ; VAR-Parameter !
ZHIGH EQU ziel + 4
convert EQU ZHIGH + 2 ; Adresse der Prozedur
quelle EQU convert + 4
QHIGH EQU quelle + 4
ConvertStr:
movea.l quelle(a6), a0 ; a0 -> quelle, lokale Variable
movea.l ziel(a6), a1 ; a1 -> ziel
move.w QHIGH(a6), d0 ; d0 := MIN( HIGH(quelle), HIGH(ziel) )
cmp.w ZHIGH(a6), d0 ;
bls.s asgnlp ;
move.w ZHIGH(a6), d0 ;
asgnlp:
move.b (a0)+, d5 ; ein Zeichen...
movem.l d0/a0/a1, -(a7); benoetigte Register retten...
subq.l #2, a7 ; Platz fuer Funktionswert ( Stackpointer
; immer wortweise veraendern )
move.b d5, -(a7) ; zu wandelndes Zeichen ( hier auch Wort! )
movea.l convert(a6), a0
jsr (a0) ; ...wandeln...
move.b (a7)+, d5 ; ...merken... ( Stack wird um 2(!) erhoeht )
movem.l (a7)+, d0/a0/a1; ...und zurueckschreiben
move.b d5, (a1)+ ; ...und kopieren
dbeq d0, asgnlp ; B: Quelle noch nicht vollstaendig kopiert
beq.s voll
moveq #0, d1 ; Default: Kopie nicht vollstaendig
move.l a0, d2 ; wird oefter gebraucht
movea.l quelle(a6), a2 ; d2 := Anzahl kopierter Zeichen( = Index )
sub.l a2, d2 ;
cmp.w QHIGH(a6), d2 ; Index > HIGH(quelle) ?
bhi.s tsteos ; B: ja, Quelle vollstaendig kopiert
tst.b (a0) ; hinter dem letzten kopierten Zeichen EOS ?
bne.s ende ; B: nein, dann Quelle nicht vollst. kopiert
tsteos:
cmp.w ZHIGH(a6), d2 ; Ist im Zielstring noch Platz fuer Nullbyte ?
bhi.s voll ; B: nein, Ziel voll
clr.b (a1) ;
voll:
moveq #1, d1
ende:
movea.l vollst(a6), a0 ; vollst VAR-Parameter !
move.b d1, (a0) ; vollst setzen
*)
INLINE( 206EH,001AH,226EH,0010H,302EH,001EH,0B06EH,0014H,6304H );
INLINE( 302EH,0014H,1A18H,48E7H,80C0H,558FH,1F05H,206EH,0016H );
INLINE( 4E90H,1A1FH,4CDFH,0301H,12C5H,57C8H,0FFE6H,671CH,7200H );
INLINE( 2408H,246EH,001AH,948AH,0B46EH,001EH,6204H,4A10H,660AH );
INLINE( 0B46EH,0014H,6202H,4211H,7201H,206EH,000CH,1081H );
END ConvertStr;
(* ------------------------------------------------------------------------- *)
PROCEDURE EqualConvStr ((* EIN/ -- *) string1,
(* EIN/ -- *) string2 : ARRAY OF CHAR;
(* EIN/ -- *) convert : CharConvert ): BOOLEAN;
(*T*)
(* VAR Index,
MaxIndex : CARDINAL; *)
BEGIN
(* Index := 0;
IF HIGH( string1 ) < HIGH( string2 ) THEN
MaxIndex := HIGH( string1 );
ELSE
MaxIndex := HIGH( string2 );
END;
(* MaxIndex = MIN( HIGH( string1 ), HIGH( string2 )) *)
LOOP
IF Index > MaxIndex THEN
EXIT;
ELSIF string1[ Index ] # string2[ Index ] THEN
(* Erst mal testen, ob die beiden Zeichen nicht schon
* ohne Konvertierung gleich sind, um moeglicherweise
* den aufwendigen Funktionsaufruf einzusparen.
*)
IF convert( string1[ Index ] ) # convert( string2[ Index ] ) THEN
RETURN( FALSE );
ELSIF string1[ Index ] = EOS THEN
RETURN( TRUE );
END; (* IF convert(.. *)
ELSIF string1[ Index ] = EOS THEN
RETURN( TRUE ); (* Wenn string1 = 0C, dann auch string2 *)
END; (* IF *)
INC( Index );
END; (* LOOP *)
(* Index = MaxIndex + 1 *)
(*
* Strings sind auch gleich, falls der eine das ARRAY fuellt
* und der andere hinter dem letzten verglichenen Zeichen
* mit "EOS" abgeschlossen ist
*)
RETURN( NOT (( HIGH( string1 ) < HIGH( string2 )) &
( string2[ Index ] # EOS ) ) OR
(( HIGH( string1 ) > HIGH( string2 )) &
( string1[ Index ] # EOS ) ) );
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
convert EQU 12
string2 EQU convert + 4
HIGH2 EQU string2 + 4
string1 EQU HIGH2 + 2
HIGH1 EQU string1 + 4
RETURN EQU HIGH1 + 2
EqualConvStr:
movea.l string1(a6), a0 ; a0 -> string1
movea.l string2(a6), a1 ; a1 -> string2
move.w HIGH1(a6), d0 ; d0 := MIN( HIGH(string1),HIGH(string2))
cmp.w HIGH2(a6), d0 ;
bls.s eqcnvlp ;
move.w HIGH2(a6), d0 ;
eqcnvlp:
move.b (a0)+, d1 ; Ist naechstes string1-Zeichen = EOS ?
beq.s tst2eos ; B: ja, Schleife zuende und string2-EOS-Test
move.b (a1)+, d3 ; sonst mit naechstem string2-Zeichen vergl.
cmp.b d1, d3
beq.s eqcnvcnt ; B: sind gleich, naechstes Zeichen
movem.l a0/a1/d0, -(a7) ; benutzte Register retten+++
move.b d3, -(a7) ; zweites Zeichen retten..
subq.l #2, a7 ; Platz fuer Funktionswert ( Stackpointer
; immer wortweise veraendern )
move.b d1, -(a7) ; zu wandelndes Zeichen ( hier auch Wort! )
movea.l convert(a6), a0
jsr (a0) ; ...wandeln...
move.b (a7)+, d1 ;
move.b (a7)+, d3 ;..zurueck
move.b d1, -(a7) ; derweil erstes Zeichen retten..
subq.l #2, a7 ; Platz fuer Funktionswert ( Stackpointer
; immer wortweise veraendern )
move.b d3, -(a7) ; zu wandelndes Zeichen ( hier auch ! )
movea.l convert(a6), a0
jsr (a0) ; ...wandeln...
move.b (a7)+, d3 ;
move.b (a7)+, d1 ;.. und zurueck
cmp.b d1, d3 ; nochmal gewandelt vergleichen
movem.l (a7)+, a0/a1/d0 ;+++ Befehl aendert nicht die Flags !
eqcnvcnt:
dbne d0, eqcnvlp ; B: sind noch gleich und nicht zuende
bne.s false ; B: unterschiedliches Zeichen entdeckt
move.w HIGH1(a6), d0 ; string1-Feld groesser als string2-Feld ?
cmp.w HIGH2(a6), d0 ;
beq.s true ; B: sind gleich, also Strings gleich
blo.s tst2eos ; B: nein, kleiner, also string2-Ende-Test
tst.b (a0) ; sonst testen, ob auch string1 zuende
beq.s true ; B: ja, Strings gleich
bra.s false ; B: string1 nicht zuende -> unterschiedl.
tst2eos:
tst.b (a1) ; string2 zuende ?
beq.s true ; B: ja, beide gleichlang
false:
moveq #0, d2
bra.s ende
true:
moveq #1, d2
ende:
move.b d2, RETURN(a6)
*)
INLINE( 206EH,0016H,226EH,0010H,302EH,001AH,0B06EH,0014H,6304H );
INLINE( 302EH,0014H,1218H,6748H,1619H,0B601H,672AH,48E7H,80C0H );
INLINE( 1F03H,558FH,1F01H,206EH,000CH,4E90H,121FH,161FH,1F01H );
INLINE( 558FH,1F03H,206EH,000CH,4E90H,161FH,121FH,0B601H,4CDFH );
INLINE( 0301H,56C8H,0FFCAH,6616H,302EH,001AH,0B06EH,0014H,6710H );
INLINE( 6506H,4A10H,670AH,6004H,4A11H,6704H,7400H,6002H,7401H );
INLINE( 1D42H,001CH );
END EqualConvStr;
(* ------------------------------------------------------------------------- *)
PROCEDURE CompareCAPStr ((* EIN/ -- *) string1,
(* EIN/ -- *) string2:ARRAY OF CHAR ):CompareResult;
(*T*)
(* VAR Index,
MaxIndex : CARDINAL; *)
BEGIN
(* Index := 0;
IF HIGH( string1 ) < HIGH( string2 ) THEN
MaxIndex := HIGH( string1 );
ELSE
MaxIndex := HIGH( string2 );
END;
(* MaxIndex = MIN( HIGH( string1 ), HIGH( string2 )) *)
LOOP
IF Index > MaxIndex THEN
EXIT;
ELSIF CAP( string1[ Index ] ) # CAP( string2[ Index ] ) THEN
(* Ergebnis aus dem ersten unterschiedlichen Zeichen bilden
*)
IF CAP( string1[ Index ] ) < CAP( string2[ Index ] ) THEN
RETURN( less );
ELSE
RETURN( greater );
END;
(* string1[ Index ] = string2[ Index ] *)
ELSIF string1[ Index ] = EOS THEN
RETURN( equal );
END; (* IF *)
INC( Index );
END; (* LOOP *)
(* Index = maxIndex + 1 *)
IF HIGH( string1 ) < HIGH( string2 ) THEN
(* Index <= HIGH( string2 ) *)
IF string2[ Index ] = EOS THEN
RETURN( equal );
ELSE
RETURN( less );
END; (* IF string2[ Index ] *)
ELSIF HIGH( string1 ) > HIGH( string2 ) THEN
(* Index <= HIGH( string1 ) *)
IF string1[ Index ] = EOS THEN
RETURN( equal );
ELSE
RETURN( greater );
END; (* IF string1[ Index ] *)
ELSE (* HIGH( string1 ) = HIGH( string2 ) *)
RETURN( equal );
END; (* IF HIGH( string1 ) < HIGH( string2 ) *);
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
string2 EQU 12
HIGH2 EQU string2 + 4
string1 EQU HIGH2 + 2
HIGH1 EQU string1 + 4
RETURN EQU HIGH1 + 2
less EQU 0
equal EQU 1
greater EQU 2
CompareCAPStr:
moveq #equal, d2 ; Default: Strings gleich
movea.l string1(a6), a0 ; a0 -> string1
movea.l string2(a6), a1 ; a1 -> string2
move.w HIGH1(a6), d0 ; d0 := MIN(HIGH(string1),HIGH(string2))
cmp.w HIGH2(a6), d0 ;
bls.s eqlp ;
move.w HIGH2(a6), d0 ;
eqlp:
move.b (a0)+, d1 ; naechstes Zeichen von <string1>
beq.s tstless ; B: <string1> zuende
move.b (a1)+, d3 ; mit naechstem von <string2>
cmp.b d1, d3 ; vergleichen
beq.s cmpnclpcnt ; B: sind gleich, naechstes Zeichen
move.b d1, d4
move.b d3, d5
andi.b #%11011111, d4 ; mal probieren ob's an Gross/Klein-
andi.b #%11011111, d5 ; schreibung liegt
cmp.b d5, d4 ;
bne.s cmp ; B: sind unterschiedlich
cmpi.b #'A', d4 ; Konvertierung klein -> gross hat natuer-
; lich nur Sinn, wenn es sich um Buchstaben
; handelt
blo.s cmp ; B: war kein Buchstabe, also ungleich
cmpi.b #'Z', d4
bls.s cmpnclpcnt ; B: Buchstabe -> gleich
cmp:
cmp.b d3, d1 ; Welcher ist also groesser ?
bhi.s gr ; B: der von <string1>
bra.s ls ; sonst der von <string2>
cmpnclpcnt:
dbra d0, eqlp ; B: bisher gleich, noch nicht alle durch
move.w HIGH1(a6), d0
cmp.w HIGH2(a6), d0
beq.s ende
blo.s tstless
tst.b (a0)
beq.s ende
gr:
moveq #greater, d2
bra.s ende
tstless:
tst.b (a1)
beq.s ende
ls:
moveq #less, d2
ende:
move.b d2, RETURN(a6)
*)
INLINE( 7401H,206EH,0012H,226EH,000CH,302EH,0016H,0B06EH,0010H );
INLINE( 6304H,302EH,0010H,1218H,6740H,1619H,0B601H,6722H,1801H );
INLINE( 1A03H,0204H,00DFH,0205H,00DFH,0B805H,660CH,0C04H,0041H );
INLINE( 6506H,0C04H,005AH,6306H,0B203H,6216H,601CH,51C8H,0FFD2H );
INLINE( 302EH,0016H,0B06EH,0010H,6710H,6508H,4A10H,670AH,7402H );
INLINE( 6006H,4A11H,6702H,7400H,1D42H,0018H );
END CompareCAPStr;
(* ------------------------------------------------------------------------- *)
PROCEDURE LeftPosConvStr ((* EIN/ -- *) muster : ARRAY OF CHAR;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) convert : CharConvert;
(* EIN/ -- *) links : BOOLEAN ): CARDINAL;
(*T*)
VAR Versuche,
MusterLaenge,
StringLaenge,
MusterIndex : CARDINAL;
BEGIN
MusterLaenge := Length( muster );
StringLaenge := Length( string );
IF start > 0 THEN DEC( start ); END;
IF ( MusterLaenge = 0 ) OR
( MusterLaenge > ( MAX(CARDINAL) - start )) OR
(( start + MusterLaenge ) > StringLaenge )
THEN
(* Bei arithmetischem Ueberlauf von <start> + <MusterLaenge>
* kann das Muster auch nicht in <string> auftreten
*)
RETURN( 0 );
ELSE
Versuche := StringLaenge - MusterLaenge - start;
(* Sooft muss das Muster maximal - um eine Position nach rechts
* versetzt - erneut mit dem String verglichen werden. Wenn dann noch
* keine Uebereinstimmung festgestellt wurde, ist <muster> nicht
* enthalten, da der Reststring kuerzer als <muster> ist.
*)
END;
LOOP
MusterIndex := 0;
(* Bis zum Musterende oder dem ersten unterschiedlichen Zeichen
* suchen
*)
WHILE ( MusterIndex < MusterLaenge ) &
( convert( string[ start ])
= convert( muster[ MusterIndex ]) )
DO
INC( start );
INC( MusterIndex );
END; (* WHILE *)
DEC( start, MusterIndex );
IF MusterIndex = MusterLaenge THEN
(* Bis zum Ende von <muster> stimmt alles ueberein,
* also gefunden
*)
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
END; (* IF MusterIndex *)
IF Versuche = 0 THEN RETURN( 0 ); END;
INC( start ); (* eins weiter rechts versuchen *)
DEC( Versuche );
END; (* LOOP *)
END LeftPosConvStr;
(* ------------------------------------------------------------------------- *)
PROCEDURE RightPosConvStr ((* EIN/ -- *) muster : ARRAY OF CHAR;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) convert : CharConvert;
(* EIN/ -- *) links : BOOLEAN ): CARDINAL;
(*T*)
VAR MusterLaenge,
StringLaenge,
MusterIndex : CARDINAL;
BEGIN
MusterLaenge := Length( muster );
StringLaenge := Length( string );
IF ( MusterLaenge = 0 ) OR ( StringLaenge = 0 ) OR
( MusterLaenge > StringLaenge )
THEN
RETURN( 0 );
END;
IF ( start = 0 ) OR ( start > StringLaenge - MusterLaenge ) THEN
(* Soweit hinten wie sinnvoll mit der Suche beginnen, d.h. es
* muessen mindestens Length( string ) Zeichen mit dem String
* verglichen werden koennen.
*)
start := StringLaenge - MusterLaenge;
ELSE
DEC( start );
END;
LOOP
MusterIndex := 0;
WHILE ( MusterIndex < MusterLaenge ) &
( convert( string[ start ]) = convert( muster[ MusterIndex ]))
DO
INC( start );
INC( MusterIndex );
END; (* WHILE *)
DEC( start, MusterIndex );
IF MusterIndex = MusterLaenge THEN (* gefunden *)
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
END; (* IF MusterIndex *)
IF start = 0 THEN RETURN( 0 ); END;
DEC( start );
END; (* LOOP *)
END RightPosConvStr;
(* ------------------------------------------------------------------------- *)
PROCEDURE LeftPosInSet ((* EIN/ -- *) charSet : ARRAY OF CHAR;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) links : BOOLEAN ): CARDINAL;
(*T*)
VAR SetIndex,
SetLaenge,
StringLaenge : CARDINAL;
Zeichen : CHAR;
BEGIN
StringLaenge := Length( string );
SetLaenge := Length( charSet );
IF start > 0 THEN
DEC( start );
END;
(* #start# = start *)
LOOP
IF start >= StringLaenge THEN RETURN( 0 ); END;
(* (#start#<=start<StringLaenge ) &
* (#start#<=i<start) & ((0<=j<SetLaenge)=>(string[i] # charSet[j]))
*)
SetIndex := 0;
Zeichen := string[ start ];
WHILE ( SetIndex < SetLaenge ) &
( charSet[ SetIndex ] # Zeichen )
DO
(* (0<=SetIndex<SetLaenge ) &
* ((0<=i<=SetIndex)=>(charSet[i] # Zeichen))
*)
INC( SetIndex );
END; (* WHILE *)
(* ((SetIndex=SetLaenge) OR (charSet[SetIndex] = Zeichen)) &
* ((0<=i<SetIndex) => (charSet[i] # Zeichen )
*)
IF SetIndex < SetLaenge THEN
(* Noch nicht die gesamte Menge durchsucht, also gefunden *)
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
END; (* IF SetIndex *)
INC( start );
END; (* LOOP *)
END LeftPosInSet;
(* ------------------------------------------------------------------------- *)
PROCEDURE RightPosInSet ((* EIN/ -- *) charSet : ARRAY OF CHAR;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) links : BOOLEAN ): CARDINAL;
(*T*)
VAR SetIndex,
SetLaenge,
StringLaenge : CARDINAL;
Zeichen : CHAR;
BEGIN
StringLaenge := Length( string );
SetLaenge := Length( charSet );
IF StringLaenge = 0 THEN RETURN( 0 ); END;
IF ( start = 0 ) OR ( start >= StringLaenge ) THEN
start := StringLaenge - 1; (* Am Ende mit der Suche beginnen *)
ELSE
DEC( start );
END;
(* #start# = start *)
LOOP
(* (0<=start<=#start# ) &
(((start<i<=#start) & (0<=j<SetLaenge))=>(string[i] # charSet[j])) *)
SetIndex := 0;
Zeichen := string[ start ];
WHILE ( SetIndex < SetLaenge ) &
( charSet[ SetIndex ] # Zeichen )
DO
(* (0<=SetIndex<SetLaenge ) &
((0<=i<=SetIndex) => (charSet[i] # Zeichen)) *)
INC( SetIndex );
END; (* WHILE *)
(* ((SetIndex=SetLaenge) OR (charSet[SetIndex] = Zeichen)) &
((0<=i<SetIndex) => (charSet[i] # Zeichen ) *)
IF SetIndex < SetLaenge THEN
(* Noch nicht die gesamte Menge durchsucht, also gefunden *)
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
END; (* IF SetIndex *)
IF start = 0 THEN RETURN( 0 ); END;
DEC( start );
END; (* LOOP *)
END RightPosInSet;
(* ------------------------------------------------------------------------- *)
PROCEDURE LeftPosInClass ((* EIN/ -- *) inClass : CharClassTest;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) links : BOOLEAN ): CARDINAL;
(*T*)
VAR StringLaenge : CARDINAL;
BEGIN
StringLaenge := Length( string );
IF start > 0 THEN DEC( start ); END;
(* #start# = start *)
WHILE ( start < StringLaenge ) & ~inClass( string[ start ] ) DO
(* (#start#<=start<StringLaenge ) &
((#start#<=i<=start)=> ~inClass(string[i])) *)
INC( start );
END; (* WHILE *)
(* (start=StringLaenge) OR inClass(string[start])) &
((#start#<=i<start)=> ~inClass(string[i]) ) *)
IF start < StringLaenge THEN
(* Noch nicht gesamter String durchsucht, also gefunden *)
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
ELSE
RETURN( 0 );
END; (* IF start *)
END LeftPosInClass;
(* ------------------------------------------------------------------------- *)
PROCEDURE RightPosInClass ((* EIN/ -- *) inClass: CharClassTest;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) links : BOOLEAN ): CARDINAL;
(*T*)
VAR StringLaenge : CARDINAL;
BEGIN
StringLaenge := Length( string );
IF StringLaenge = 0 THEN RETURN( 0 ); END;
IF ( start = 0 ) OR ( start >= StringLaenge ) THEN
start := StringLaenge - 1;
(* Am Ende mit der Suche beginnen;
* 0 <=start <= MAX(INTEGER) < StringLaenge
*)
ELSE
DEC( start );
END;
WHILE ( VAL( INTEGER, start ) >= 0 ) & ~inClass( string[ start ] ) DO
DEC( VAL( INTEGER, start ));
END; (* WHILE *)
IF VAL( INTEGER, start ) >= 0 THEN
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
ELSE
RETURN( 0 );
END; (* IF VAL( *)
END RightPosInClass;
(* ------------------------------------------------------------------------- *)
PROCEDURE LeftPosNotInSet ((* EIN/ -- *) charSet: ARRAY OF CHAR;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) links : BOOLEAN ): CARDINAL;
(*T*)
(* Das gleiche wie "LeftPosInSet", nur Abfrage: SetIndex = SetLaenge *)
VAR SetIndex,
SetLaenge,
StringLaenge : CARDINAL;
Zeichen : CHAR;
BEGIN
StringLaenge := Length( string );
SetLaenge := Length( charSet );
IF start > 0 THEN DEC( start ); END;
LOOP
IF start >= StringLaenge THEN
RETURN( 0 );
END;
SetIndex := 0;
Zeichen := string[ start ];
WHILE ( SetIndex < SetLaenge ) &
( charSet[ SetIndex ] # Zeichen )
DO
INC( SetIndex );
END; (* WHILE *)
IF SetIndex = SetLaenge THEN (* nicht in <charSet> gefunden *)
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
END;
INC( start );
END;
END LeftPosNotInSet;
(* ------------------------------------------------------------------------- *)
PROCEDURE RightPosNotInSet ((* EIN/ -- *) charSet: ARRAY OF CHAR;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) links : BOOLEAN ): CARDINAL;
(*T*)
(* Das gleiche wie "RightPosInSet", nur Abfrage: SetIndex = SetLaenge *)
VAR SetIndex,
SetLaenge,
StringLaenge : CARDINAL;
Zeichen : CHAR;
BEGIN
StringLaenge := Length( string );
SetLaenge := Length( charSet );
IF ( start = 0 ) OR ( start >= StringLaenge ) THEN
start := StringLaenge - 1;
ELSE
DEC( start );
END;
LOOP
SetIndex := 0;
Zeichen := string[ start ];
WHILE ( SetIndex < SetLaenge ) &
( charSet[ SetIndex ] # Zeichen )
DO
INC( SetIndex );
END;
IF SetIndex = SetLaenge THEN (* nicht in <charSet> gefunden *)
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
END;
IF start = 0 THEN
RETURN( 0 );
END;
DEC( start );
END;
END RightPosNotInSet;
(* ------------------------------------------------------------------------- *)
PROCEDURE LeftPosNotInClass ((* EIN/ -- *) inClass: CharClassTest;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) links : BOOLEAN ):CARDINAL;
(*T*)
(* das gleiche wie "LeftPosInClass", nur: inClass() <-> ~inClass() *)
VAR StringLaenge : CARDINAL;
BEGIN
StringLaenge := Length( string );
IF start > 0 THEN DEC( start ); END;
WHILE ( start < StringLaenge ) & inClass( string[ start ] ) DO
INC( start );
END;
IF start < StringLaenge THEN
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
ELSE
RETURN( 0 );
END;
END LeftPosNotInClass;
(* ------------------------------------------------------------------------- *)
PROCEDURE RightPosNotInClass ((* EIN/ -- *) inClass: CharClassTest;
(* EIN/ -- *) start : CARDINAL;
(* EIN/ -- *) string : ARRAY OF CHAR;
(* EIN/ -- *) links : BOOLEAN ):CARDINAL;
(*T*)
(* das gleiche wie "RightPosInClass", nur: inClass() <-> ~inClass() *)
VAR StringLaenge : CARDINAL;
BEGIN
StringLaenge := Length( string );
IF StringLaenge = 0 THEN RETURN( 0 ); END;
IF ( start = 0 ) OR ( start >= StringLaenge ) THEN
start := StringLaenge - 1;
ELSE
DEC( start );
END;
WHILE ( VAL( INTEGER, start ) >= 0 ) & inClass( string[ start ] ) DO
DEC( start );
END;
IF VAL( INTEGER, start ) >= 0 THEN
IF links THEN
RETURN( start + 1 );
ELSE
RETURN( StringLaenge - start );
END;
ELSE
RETURN( 0 );
END;
END RightPosNotInClass;
(* ------------------------------------------------------------------------- *)
PROCEDURE TrimLeft ((* EIN/AUS *) VAR string : ARRAY OF CHAR );
(*T*)
VAR ZielIndex,
QuellIndex : CARDINAL;
BEGIN
QuellIndex := 0; ZielIndex := 0;
(* erstes Zeichen finden, dass nicht Blank ist *)
WHILE ( QuellIndex <= VAL( CARDINAL, HIGH( string ))) &
( string[ QuellIndex ] = ' ' )
DO
INC( QuellIndex );
END;
(* ( 0 <= i < QuellIndex ==> string[ i ] = ' ' ) & *)
(* ( QuellIndex < Length( string ) ==> string[ QuellIndex ] # ' ' ) & *)
(* ( QuellIndex <= Length( string ) *)
IF QuellIndex > 0 THEN (* nur umkopieren, wenn Blanks am Anfang *)
WHILE ( QuellIndex <= VAL( CARDINAL, HIGH( string ))) &
( string[ QuellIndex ] # EOS )
DO
string[ ZielIndex ] := string[ QuellIndex ];
INC( ZielIndex ); INC( QuellIndex );
END;
(* Da mindestens um ein Zeichen nach links kopiert wird, *)
(* ist auf jeden Fall Platz fuer das Nullbyte *)
string[ ZielIndex ] := EOS;
END;
END TrimLeft;
(* ------------------------------------------------------------------------- *)
PROCEDURE TrimRight ((* EIN/AUS *) VAR string : ARRAY OF CHAR );
(*T*)
(* VAR Index : INTEGER; *)
BEGIN
(* Index := Length( string );
(* letztes Zeichen finden, dass kein Blank ist *)
REPEAT
DEC( Index );
(* (-1<=Index<Length(string) ) &
* ((Index<i<Length(string) => (string[i]#' '))
*)
UNTIL ( Index < 0 ) OR ( string[ Index ] # ' ' );
(* ((Index<0) OR (string[Index]#' ') ) &
* ((Index<i<Length(string) => (string[i]#' '))
*)
IF Index < HIGH( string ) THEN
string[ Index + 1 ] := EOS;
END;
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
string EQU 12
HIGH EQU string + 4
TrimRight:
movea.l string(a6), a0 ;
move.w HIGH(a6), d0 ;
move.w d0, d2 ;
lenlp:
tst.b (a0)+ ;
dbeq d0, lenlp ;
bne.s clclen ; B: String durch Feldende abgeschlossen:
; steht schon hinter letztem Stringzeichen
subq.l #1, a0 ; a0 -> eins hinter letztem Stringzeichen,
; statt hinter dem Nullbyte
clclen:
sub.w d0, d2 ; d2 := Length(string)
moveq #' ', d1 ; fuer schnellen Vergleich
moveq #0, d7 ; damit die Schleife nicht wegen NE abbricht
bra.s blklp + 2
blklp:
cmp.b -(a0), d1
dbne d2, blklp ; B: Bisher nur Blanks, String nicht zuende
beq.s clcidx ; B: <string> nur Blanks, a0 -> erstes Zeichen
addq.l #1, a0 ; a0 -> erstes Blank hinter letztem Buchst.
clcidx:
move.l a0, d1
movea.l string(a6), a1
sub.l a1, d1 ; d1 := Index dieses Blanks
cmp.w HIGH(a6), d1 ;
bhi.s ende ; B: <string> fuellt Feld aus und hat keine
; abschliessenden Blanks
clr.b (a0)
ende:
*)
INLINE( 206EH,000CH,302EH,0010H,3400H,4A18H,57C8H,0FFFCH,6602H );
INLINE( 5388H,9440H,7220H,7E00H,6002H,0B220H,56CAH,0FFFCH,6702H );
INLINE( 5288H,2208H,226EH,000CH,9289H,0B26EH,0010H,6202H,4210H );
END TrimRight;
(* ------------------------------------------------------------------------- *)
PROCEDURE TrimStr ((* EIN/AUS *) VAR string : ARRAY OF CHAR );
(*T*)
BEGIN
TrimLeft( string );
TrimRight( string );
END TrimStr;
END XStrings.